package com.ruoyi.newSystem.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.annotations.VisibleForTesting;
import com.ruoyi.common.constant.ErrorCodeConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.PageResult;
import com.ruoyi.common.core.domain.entity.*;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.ValidException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StpSystemUtil;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.common.utils.sign.Md5Utils;
import com.ruoyi.newSystem.bean.input.UserPageReqVO;
import com.ruoyi.newSystem.bean.input.UserUpdateReqVO;
import com.ruoyi.newSystem.mapper.AdminUserMapper;
import com.ruoyi.newSystem.service.AdminUserService;
import com.ruoyi.newSystem.service.DeptService;
import com.ruoyi.newSystem.service.PermissionService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;

import static io.micrometer.core.instrument.binder.http.HttpRequestTags.exception;


/**
 * 后台用户 Service 实现类
 *
 * @author 后台源码
 */
@Service("adminUserService")
@Slf4j
public class AdminUserServiceImpl implements AdminUserService {


    @Resource
    private AdminUserMapper userMapper;
    @Resource
    private DeptService deptService;

    @Resource
    private PermissionService permissionService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public AdminUserDO createUser(AdminUserDO adminUserDO) throws Exception {

        AdminUserDO user = userMapper.selectByUsername(adminUserDO.getUsername());

        if (user != null) {
            throw new ValidException("用户名存在");
        }

        adminUserDO.setUserType(2);
        adminUserDO.setCreateTime(LocalDateTime.now());
        if (StringUtils.isBlank(adminUserDO.getNickname())) {
            adminUserDO.setNickname(adminUserDO.getUsername());
        }
        adminUserDO.setDeleted(0);
        adminUserDO.setStatus(1); // 默认开启

        //创建用户
        userMapper.insert(adminUserDO);
        //创建用户后给用户一个默认角色
        Set<Long> roleIds = new HashSet<>();
        roleIds.add(2L);
        permissionService.assignUserRole(adminUserDO.getId(), roleIds);
        return adminUserDO;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(UserUpdateReqVO reqVO) {

        // 更新用户
        AdminUserDO updateObj = new AdminUserDO();
        BeanUtils.copyProperties(reqVO, updateObj);
        userMapper.updateById(updateObj);

    }

    @Override
    public PageResult<AdminUserDO> getUserPage(UserPageReqVO reqVO) {
        return userMapper.selectPage(reqVO, getDeptCondition(reqVO.getDeptId()));
    }

    @Override
    public void updateUserPassword(Long id, String oldPassword, String newPassword) {
        // 校验旧密码密码

        AdminUserDO adminUserDO1 = userMapper.selectOne(AdminUserDO::getId, id);
        if (!adminUserDO1.getPassword().equals(oldPassword)) {
            throw new RuntimeException("旧密码错误，请重新输入");
        }
        if (oldPassword.equals(newPassword)) {
            throw new RuntimeException("新密码不能与旧密码一样");
        }
        // 执行更新s
        AdminUserDO adminUserDO = new AdminUserDO();
        adminUserDO.setId(id);
        adminUserDO.setPassword(newPassword); // 加密密码
        //更新修改密码时间
        adminUserDO.setPasswordTime(DateUtils.getTime());
        userMapper.updateById(adminUserDO);
    }

    @Override
    public AdminUserDO getUserByUsername(String username) {
        return userMapper.selectByUsername(username);
    }

    @Override
    public AdminUserDO getUserByUserId(Long id) {
        return userMapper.selectById(id);
    }

    private Set<Long> getDeptCondition(Long deptId) {
        if (deptId == null) {
            return Collections.emptySet();
        }
        Set<Long> deptIds = CollectionUtils.convertSet(deptService.getChildDeptList(deptId), DeptDO::getId);
        deptIds.add(deptId); // 包括自身
        return deptIds;
    }


    @VisibleForTesting
    void validateUsernameUnique(Long id, String username) throws Exception {
        if (StrUtil.isBlank(username)) {
            return;
        }
        AdminUserDO user = userMapper.selectByUsername(username);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw new Exception("用户不存在");
        }
        if (!user.getId().equals(id)) {
            throw new Exception("用户不存在");
        }
    }

    public AdminUserDO getUserByUnionid(String unionid) {
        return userMapper.selectOne(AdminUserDO::getDingUnionid, unionid);
    }

    @Override
    public AdminUserDO getUserNameAndPassword(String username, String password) {
        QueryWrapper<AdminUserDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username).eq("password", password).eq("deleted", 0);
        return userMapper.selectOne(queryWrapper);
    }


    @Override
    public void getAllPermissionsSetCache(Long id) {
        UserInfo userInfo = new UserInfo();
        QueryWrapper<AdminUserDO> objectQueryWrapper = new QueryWrapper<AdminUserDO>();
        objectQueryWrapper.eq("id", id);
        //获取用户信息
        List<AdminUserDO> adminUserDOS = userMapper.selectList(objectQueryWrapper);
        userInfo.setAdminUserDO(adminUserDOS.get(0));
        //获取用户拥有的角色
        List<RoleDO> userRoleByUserId = permissionService.getUserRoleByUserId(id);
        userInfo.setRoles(userRoleByUserId);
        //获取用户拥有的菜单
        List<MenuDO> menuByUserIds = permissionService.getMenuByUserIds(id);
        userInfo.setMenus(menuByUserIds);

        //用户数据权限
        HashSet<String> strings = new HashSet<>();
        for (RoleDO roleDO : userRoleByUserId) {
            if (roleDO.getDataScopeAccessIds() != null) {
                strings.addAll(roleDO.getDataScopeAccessIds());
            }
        }
        userInfo.setDataScopeData(JSONArray.toJSONString(strings));
        StpSystemUtil.setUserInfo(userInfo);
    }

    @Override
    public AjaxResult isPasswordUpdate() {
        UserInfo userInfo = StpSystemUtil.getUserInfo();
        String iniPassword = Md5Utils.hash("000000");
        boolean equals = iniPassword.equals(userInfo.getAdminUserDO().getPassword());
        //1 代表使用初始密码 2 代表使用超过30天 3 代表无需修改
        HashMap<String, Integer> objectObjectHashMap = new HashMap<>();
        if (equals) {
            objectObjectHashMap.put("status", 1);
            return AjaxResult.success(objectObjectHashMap);
        }

        //获取当前时间和密码最后被修改时间
        LocalDateTime now = LocalDateTime.now();
        String passwordTime = userInfo.getAdminUserDO().getPasswordTime();
        LocalDateTime parse = LocalDateTimeUtil.parse(passwordTime, DateUtils.YYYY_MM_DD_HH_MM_SS);

        long daysBetween = ChronoUnit.DAYS.between(parse, now);
        // 取绝对值来判断是否相差30天（不考虑先后顺序因为我永远是拿今天时间来比对，注册时间不可能比今天晚）
        if (Math.abs(daysBetween) >= 30) {
            objectObjectHashMap.put("status", 2);
            return AjaxResult.success(objectObjectHashMap);
        }
        objectObjectHashMap.put("status", 3);
        return AjaxResult.success(objectObjectHashMap);
    }

    @Override
    public void updateUserStatus(Long id, Integer status) {
        // 校验用户存在
        validateUserExists(id);
        // 更新状态
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setStatus(status);
        userMapper.updateById(updateObj);
    }

    @VisibleForTesting
    void validateUserExists(Long id) {
        if (id == null) {
            throw new ValidException("用户id为空");
        }
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw new RuntimeException("用户不能为空");
        }
    }

}
